﻿module Sustainalytics.Events {

    import Common = Sustainalytics.Common;
    import Pager = Sustainalytics.Pager;

    // Events List controller
    export class EventsListController {

        // specifies whether current controller is in loading state
        public isLoading: boolean;

        // controller scope
        public $scope: ng.IScope;

        // services
        private $q: ng.IQService;
        private $location: ng.ILocationService;

        private eventsService: EventsService;
        private eventsTypesService: EventsTypesService;
        private eventsStatusesService: EventsStatusesService;

        private notificationFactory: INotificationFactory;

       
        // paged list of news
        public eventsPaged: Common.PagedList<EventDto>;
        // news filter
        public  eventsFilter: EventsFilter;

        // whether all items are selected
        public selectAll: boolean;
        // order by column
        public orderByCol: string;
        // order by direction
        public orderByColAsc: boolean;

        // events types
        public eventsTypes: EventType[];

        // events types
        public eventsStatusesDic: any;
        public eventsStatuses: EventStatus[];



        // Ctor.
        constructor($scope: ng.IScope, $q: ng.IQService, $location: ng.ILocationService, EventsService, EventsTypesService, EventsStatusesService, notificationFactory: INotificationFactory) {
            var ctx = this;

            $scope['eventsList'] = ctx;

            ctx.$scope = $scope;
            ctx.$q = $q;
            ctx.$location = $location;
           
            ctx.eventsService = EventsService;
            ctx.eventsTypesService = EventsTypesService;
            ctx.eventsStatusesService = EventsStatusesService;
            ctx.notificationFactory = notificationFactory;

            ctx.eventsFilter = new EventsFilter();
            ctx.orderByCol = 'StartDate';
            ctx.orderByColAsc = false;

            // load all required data
            var loadPromise: ng.IPromise<{}> = ctx.load();

            // handle pager changed event
            ctx.$scope.$on('pagerChanged', function (event, pager) {
                ctx.getEvents();
            });

            // notify parents that the controller was created
            $scope.$emit('eventsList.created', ctx);
            $scope["myform"] = {};
            ctx.handleSelectAll();

            ctx.handleFilterChanged();

        }


        // news filter term changed
        private handleFilterChanged() {
            var ctx = this;
            this.$scope.$watch('eventsList.eventsFilter.type', function () {
                ctx.getEvents(1);
            });
        }

        // load all required info
        private load(): ng.IPromise<{}> {
            var ctx = this;

            ctx.isLoading = true;

            // populate events types
            var eventsTypesPromise = ctx.populateEventsTypes();

            var statusesPromise = ctx.populateEventsStatuses();

            // create a promise based on all promises
            var allPromise = ctx.$q.all([eventsTypesPromise, statusesPromise]);

            allPromise.finally(function () {
                ctx.isLoading = false;
            });

            return allPromise;
        }


        // populate all events Types
        private populateEventsTypes(): ng.IPromise<EventType[]> {
            var ctx = this;

            var getPromise: ng.IPromise<EventType[]> = ctx.eventsTypesService.getEventsTypes();

            getPromise.then(function (eventsTypes: EventType[]) {
                ctx.eventsTypes = eventsTypes;
            });

            return getPromise;
        }

        // populate all events Statuses
        private populateEventsStatuses(): ng.IPromise<EventStatus[]> {
            var ctx = this;

            var getPromise: ng.IPromise<EventStatus[]> = ctx.eventsStatusesService.getEventsStatuses();

            getPromise.then(function (eventsStatuses: EventType[]) {
                ctx.eventsStatusesDic = {};
                ctx.eventsStatuses = eventsStatuses;
                $(eventsStatuses).each(function () { ctx.eventsStatusesDic[this.id] = this; });
            });

            return getPromise;
        }


        // get list of news - paged and filtered
        public getEvents(pageIndex?: number, pageSize?: number) {

            var ctx = this;

            ctx.isLoading = true;

            // get current pager
            var pager: Pager.PagerController = ctx.$scope['pager'];

            if (!pager)
                return;

            if (pageIndex != null)
                pager.pagingOptions.pageIndex = pageIndex;

            if (pageSize != null)
                pager.pagingOptions.pageSize = pageSize;

            // create order by criteria
            var orderBy = ctx.orderByCol && ctx.orderByCol !== '' ? [ctx.orderByCol] : null;
            
            // get news items
            var eventsPagedPromise: ng.IPromise<Common.PagedList<EventDto>> = ctx.eventsService.getEventsPaged(ctx.eventsFilter, pager.skipCount(), pager.takeCount(), orderBy, ctx.orderByColAsc);

            // on success set list of events
            eventsPagedPromise.then(function (eventsPaged) {
                var currentPage = pager.pagingOptions.pageIndex;
                ctx.eventsPaged = eventsPaged;
                pager.loadPagingFromPagedList(eventsPaged);

                // if current page is empty but there are items then go to previous page
                if (ctx.eventsPaged.totalItemsCount > 0 && ctx.eventsPaged.items.length == 0 && ctx.eventsPaged.pagingOptions.pageIndex > 1) {
                    var prevPage = Math.min(ctx.eventsPaged.totalPageCount, currentPage - 1);
                    ctx.getEvents(prevPage);
                }
            });

            eventsPagedPromise.finally(function () {
                ctx.isLoading = false;
            });
        }

        // execute search and apply filter
        public search() {
            var ctx = this;
             
            if (ctx.$scope["myform"] && ctx.$scope["myform"].$invalid) {
                ctx.notificationFactory.error('', 'Please enter a search criteria of at least 3 characters.');
                return;
            }

            ctx.getEvents(1);
        }

        // get selected items
        public getSelectedItems(): EventDto[] {
            var ctx = this;

            if (ctx.eventsPaged && ctx.eventsPaged.items && ctx.eventsPaged.items.length > 0) {
                var items = $(ctx.eventsPaged.items).filter(function () { return this.selected; }).get();
                return items;
            }

            return new Array();
        }


        // select all
        private handleSelectAll() {
            var ctx = this;

            ctx.$scope.$watch('eventsList.selectAll', function () {
                if (ctx.eventsPaged && ctx.eventsPaged.items && ctx.eventsPaged.items.length > 0) {
                        $(ctx.eventsPaged.items).each(function () { this.selected = ctx.selectAll; });
                }
            });
        }

        // when orderBy changes execute a get()
        public changeOrderBy(col) {
            var ctx = this;
            var oldCol = ctx.orderByCol;

            if (oldCol === col) {
                ctx.orderByColAsc = !ctx.orderByColAsc;
            }
            else {
                ctx.orderByCol = col;
                ctx.orderByColAsc = true;
            }

            ctx.getEvents(1);
        }


        public addEvent() {
            this.$location.path('/events/add');
        }
        public editEvent(id: string) {
            this.$location.path('/events/edit/' + id);
        }

        public deleteSelectedEvents(): ng.IPromise<Object> {

            var ctx = this;
            var def = ctx.$q.defer();
            var items = ctx.getSelectedItems();

            // check we have something to delete 
            if (items.length == 0) {
                //‘Please make a selection and try again’          
                ctx.notificationFactory.error('', "Please make a selection and try again.");
                def.resolve();
                return def.promise;
            }

            var draft = ctx.eventsStatusesService.statuses.Draft;
            var eventsIds: string[] = $(items).filter((i) => items[i].status === draft).map(function () { return this.id; }).get();

            if (eventsIds.length != items.length) {
                ctx.notificationFactory.error('', "Only items in status Draft can be deleted, please check your selection and try again.");

                def.resolve();
                return def.promise;
            }

            if (confirm(eventsIds.length + ' item(s) will be deleted.') == false) {
                var def = ctx.$q.defer();
                def.resolve();
                return def.promise;
            }

            // ok to delete 
            ctx.isLoading = true;

            var eventsPatch = new EventsPatch();
            eventsPatch.deleteItems = eventsIds;
            var promise = ctx.eventsService.patchEvents(eventsPatch);
            promise
                .then(
                    () => ctx.notificationFactory.success('The items were deleted.'), //success
                    () => ctx.notificationFactory.error('', 'Failed to deleted all selected the items!')) //error
                .finally(() => {
                    ctx.isLoading = false;
                    ctx.getEvents();
                });

            def.resolve(promise);
            return def.promise;
        }

        public publishSelectedEvents(): ng.IPromise<Object> {

            var ctx = this;
            var def = ctx.$q.defer();
            var items = ctx.getSelectedItems();

            // check we have something to delete 
            if (items.length == 0) {
                //‘Please make a selection and try again’          
                ctx.notificationFactory.error('', "Please make a selection and try again.");
                def.resolve();
                return def.promise;
            }

            var draft = ctx.eventsStatusesService.statuses.Draft;
            var eventsIds: string[] = $(items).filter((i) => items[i].status === draft).map(function () { return this.id; }).get();

            if (eventsIds.length != items.length) {
                ctx.notificationFactory.error('', "Only items in status Draft can be published, please check your selection and try again.");

                def.resolve();
                return def.promise;
            }

            if (confirm(eventsIds.length + ' items will be published.') == false) {
                var def = ctx.$q.defer();
                def.resolve();
                return def.promise;
            }

            // ok to delete 
            ctx.isLoading = true;

            var eventsPatch = new EventsPatch();
            eventsPatch.publishItems = eventsIds;
            var promise = ctx.eventsService.patchEvents(eventsPatch);

            promise
                .then(
                () => ctx.notificationFactory.success('The items were published.'), //success
                () => ctx.notificationFactory.error('', 'Failed to publish all the items!')) //error
                .finally(() => {
                    ctx.isLoading = false;
                    ctx.getEvents();
                });

            def.resolve(promise);
            return def.promise;
        }

    }

    // register controller with News Angular module
    angular.module('Sustainalytics.Events').controller('EventsListController', function ($scope: ng.IScope, $q: ng.IQService, $location: ng.ILocationService, EventsService, EventsTypesService, EventsStatusesService, notificationFactory: INotificationFactory) {
        var ctrl = new EventsListController($scope, $q, $location, EventsService, EventsTypesService, EventsStatusesService, notificationFactory);
        return ctrl;
    });
}